package commands;

import indexes.BattingIndex;
import indexes.PlayerIDIndex;
import indexes.PlayerNameIndex;

import java.util.List;
import java.io.*;
import java.util.NoSuchElementException;
import java.util.logging.Logger;

import java.io.File;

import util.BattingDatabaseFile;
import util.DatabaseFile;
import util.PlayerLogger;

import main.PlayerDB;

/**
 * The command class models a command from a script
 * for building these databases.  Any subclasses 
 * know how to handle their particular arguments
 * (given in lists of strings). 
 * @author bfults (Brian Fults - 905084698)
 *
 */
public abstract class Command
{
    
    private static final String DIVIDER = "------------------";
    //Begin nested enum Commands
    /**
     * Commands are identifed in an enumerated type
     * for comparison.
     */
    public enum Commands
    {
        
        IMPORT("import"),
        IMPORT_BATTING("import_batting"),
        IDENTIFY_BY_NAME("identify_by_name"),
        SHOW_STATS_FOR("show_stats_for"),
        SHOW_BATTING_DETAILS_FOR("show_batting_details_for"),
        SHOW_BATTING_SUMMARY_FOR("show_batting_summary_for"),
        SHOW_BATTING_SUMMARY_FOR_RANGE("show_batting_summary_for_range"),
        REMOVE("remove"),
        SHOW_INDEX_FOR("show_index_for"),
        EXIT("exit");
        
        
        private final String command_text;
        
        private Commands(String command_text)
        {
            this.command_text = command_text;
        }
        
        public String toString()
        {
            return this.command_text;
        }
        
        /**
         * Attempts to convert a string to a known command.
         * @param toConvert
         * @return the converted Command
         * @throws IllegalArgumentException If the string isn't a command.
         */
        public static Commands toCommand(String toConvert) throws IllegalArgumentException
        {
            if (toConvert == null)
            {
                throw new NullPointerException("Null argument to toCommand!");
            }
            for (Commands command: Commands.values())
            {
                if (toConvert.equalsIgnoreCase( command.toString() ))
                    return command;
            }
            throw new IllegalArgumentException("Command not found!");
        }
    }//End nested enum Commands
    
    private List<String> arguments;
    
    protected List<String> getArguments()
    {
        return arguments;
    }
    /**
     * This method must be implemented by all subclasses.
     * Command.execute performs the action for the given command.
     * @param idIndex The index of playerIds
     * @param nameIndex The index of playerNames
     * @param logger Stream to send log information to.
     * @param database player database
     * @param battingIndex TODO
     * @param battingDatabase TODO
     * @return the status of the program - execution continues as long
     * as the command returns true.
     * @throws IOException 
     */
    public abstract boolean execute(PlayerIDIndex idIndex, PlayerNameIndex nameIndex, PlayerLogger logger, DatabaseFile database, BattingIndex battingIndex, BattingDatabaseFile battingDatabase) throws IOException;
    
    /**
     * All commands have an argument list, even if it is empty.
     * @param arguments
     */
    protected Command(List<String> arguments)
    {
        this.arguments = arguments;
    }
    
    protected void setArgs(List<String> arguments)
    {
        this.arguments = arguments;
    }
    /**
     * Returns the divider used to separate arguments in a command's text version.
     * @return string divider
     */
    public static String getDivider()
    {
        return DIVIDER;
    }

}
